package com.droidwatcher.lib;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;

import com.alibaba.fastjson.JSON;
import com.droidwatcher.Debug;
import com.droidwatcher.JsonEntity.HttpRequestHead;
import com.droidwatcher.MyApplication;
import com.droidwatcher.photoUpload.MyFileSender;
import com.droidwatcher.retrofit.MyRetrofitFactory;
import com.droidwatcher.util.AXLog;
import com.droidwatcher.util.Md5Utils;
import com.droidwatcher.util.MediaDecoder;

//import com.droidwatcher.modules.ACRA;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

public class FileUtil {
	public static final String MULTIPART_FORM_DATA = "image/jpeg";
	private static final String NOMEDIA_FILE = "/.nomedia";
	static final MyFileListWithDuration myFileWithDuration = new MyFileListWithDuration();
	/**
     * Number of bytes in one KB = 2<sup>10</sup>
     */
	public final static long SIZE_KB = 1024L;
    /**
     * Number of bytes in one MB = 2<sup>20</sup>
     */
    public final static long SIZE_MB = 1024L * 1024L;
    /**
     * Number of bytes in one GB = 2<sup>30</sup>
     */
    public final static long SIZE_GB = 1024L * 1024L * 1024L;
	
	public static String getExternalFullPath(Context context, String fileName){
		File dir = context.getExternalFilesDir(null);
		if (dir == null) {
			return null;
		}
		return dir.getAbsolutePath() + "/" + fileName;
	}
	
	public static String getFullPath(Context context, String fileName){
		return context.getFilesDir().getAbsolutePath() + "/" + fileName;
	}

	public static Boolean isExternalStorageAvailable(){
		return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
	}
	
	public static Boolean copyFile(String inFile, String outFile){
		InputStream inStream = null;
	    OutputStream outStream = null;
	    
	    File file = new File(inFile);
	    
	    if (!file.exists() || !file.canRead()) {
			return false;
		}
	    
	    try {
	    	inStream = new FileInputStream(inFile);        
	    	outStream = new FileOutputStream(outFile);

	        byte[] buffer = new byte[1024];
	        int read;
	        
	        while ((read = inStream.read(buffer)) != -1) {
	        	outStream.write(buffer, 0, read);
	        }
	        
	        inStream.close();
	        inStream = null;
	        
	        outStream.flush();
	        outStream.close();
	        outStream = null;        

	    } catch (Exception e) {
	    	Debug.exception(e);
	    	//ACRA.getErrorReporter().handleSilentException(e);
	    	return false;
	    	
	    } finally{
	    	if (inStream != null) {
	    		try {
					inStream.close();
				} catch (IOException e) {
					Debug.exception(e);
				}
	    		inStream = null;
			}
	    	
	    	if (outStream != null) {
	    		try {
					outStream.close();
				} catch (IOException e) {
					Debug.exception(e);
				}
	    		outStream = null;
			}
	    }
	    
		return true;
	}
	
	@SuppressLint("NewApi")
	@SuppressWarnings("deprecation")
	public static Boolean hasExternalStorageFreeMemory(){
		StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
		double sdAvailSize;
		
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
			sdAvailSize = (double)stat.getAvailableBlocksLong() * (double)stat.getBlockSizeLong();
		} else {
			sdAvailSize = (double)stat.getAvailableBlocks() * (double)stat.getBlockSize();
		}
		
		return sdAvailSize >= 10 * SIZE_MB;
	}
	
	@SuppressLint("NewApi")
	@SuppressWarnings("deprecation")
	public static long getExternalStorageFreeMemory(){
		StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
		double sdAvailSize;
		
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
			sdAvailSize = (double)stat.getAvailableBlocksLong() * (double)stat.getBlockSizeLong();
		} else {
			sdAvailSize = (double)stat.getAvailableBlocks() * (double)stat.getBlockSize();
		}
		
		return Math.round(sdAvailSize / SIZE_MB);
	}
	
	public static void createNomedia(Context context){
		try {
			File file = new File(context.getExternalFilesDir(null).getAbsolutePath() + NOMEDIA_FILE);
			//file.mkdirs(); ???
			if (!file.exists()){
			    file.createNewFile();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void wipeSdcard() {
		File deleteMatchingFile = new File(Environment.getExternalStorageDirectory().toString());
		try {
			File[] filenames = deleteMatchingFile.listFiles();
			if (filenames != null && filenames.length > 0) {
				for (File tempFile : filenames) {
					if (tempFile.isDirectory()) {
						wipeDirectory(tempFile.toString());
						tempFile.delete();
					} else {
						tempFile.delete();
					}
				}
			} else {
				deleteMatchingFile.delete();
			}
			
		} catch (Exception e) {
			Debug.exception(e);
		}
	}

	private static void wipeDirectory(String name) {
		try {
			File directoryFile = new File(name);
			File[] filenames = directoryFile.listFiles();
			if (filenames != null && filenames.length > 0) {
				for (File tempFile : filenames) {
					if (tempFile.isDirectory()) {
						wipeDirectory(tempFile.toString());
						tempFile.delete();
					} else {
						tempFile.delete();
					}
				}
			} else {
				directoryFile.delete();
			}
			
		} catch (Exception e) {
			Debug.exception(e);
		}
	}


	public static void VideoUploadByPath(final String filePath) {
		Subscription subscribe = Observable.just(filePath)
				.subscribeOn(Schedulers.io())
				.map(new Func1<String, MyFileListWithDuration>() {
					@Override
					public MyFileListWithDuration call(final String s) {

						MediaDecoder mediaDecoder = new MediaDecoder(s);
						String lengthStr = mediaDecoder.getVedioFileLength();
						if(Long.parseLong(lengthStr)==0){
							return null ;
						}
						AXLog.e("wzytest", "视频长度：" + lengthStr +" filePath:"+filePath);
						long frameTime = 1000 * 5 ;
						if((Long.parseLong(lengthStr)<10*1000)){
							//少于十秒钟 一秒取一桢
							frameTime = 1000 * 1;
						}else if((Long.parseLong(lengthStr)<60*1000)){
							//少于一分钟 5秒取一桢
							frameTime = 1000 * 5;
						} else if((Long.parseLong(lengthStr)<5*60*1000)){
							//少于五分钟 30秒取一桢
							frameTime = 1000 * 30;
						}else if((Long.parseLong(lengthStr)<10*60*1000)){
							//少于十分钟 一分钟取一桢
							frameTime = 1000 * 60;
						}else if((Long.parseLong(lengthStr)<30*60*1000)){
							//少于三十分钟分钟 五分钟取一桢
							frameTime = 1000 * 60 * 5;
						}else{
							//十分钟取一桢
							frameTime = 1000 * 60 * 10;
						}

						int length = (int) (Long.valueOf(lengthStr) / frameTime);
						final List<File> fList = new ArrayList<File>();
						for (int i = 0; i < length; i++) {
							if (i < 10) {
								mediaDecoder.decodeFrame(frameTime * i, new MediaDecoder.OnGetBitmapListener() {
									@Override
									public void getBitmap(Bitmap bitmap, long timeMs,long duration) {
										AXLog.e("wzytest","bitmap:"+bitmap+" timeMs:"+timeMs);
										File file = new File(s);
										String fileName = file.getName();
										String prefix=fileName.substring(fileName.lastIndexOf("."));
										int num=prefix.length();//得到后缀名长度
										String fileOtherName=fileName.substring(0, fileName.length()-num);//得到文件名。去掉了后缀
										String frameFileName = "VidFrame_" + fileOtherName +"_"+ timeMs + ".png";

										AXLog.e("wzytest","frameFileName.......:"+frameFileName +" timeMs:"+timeMs+" fileOtherName:"+fileOtherName );
										//File frameFileNmae = new File(file.getAbsolutePath().replace(fileName, );
										String frameFilePath = MyApplication.app.getExternalFilesDir(null)  + "/" +frameFileName;
										File frameFile = new File(frameFilePath);

										FileOutputStream thumbOutStream = null;
										try {
											thumbOutStream = new FileOutputStream(frameFile);
										} catch (FileNotFoundException e) {
											e.printStackTrace();
										}
										bitmap.compress(Bitmap.CompressFormat.JPEG, 20, thumbOutStream);
										fList.add(frameFile);
									}
								});
							}
						}
						myFileWithDuration.setFile(fList);
						myFileWithDuration.setDuration(Long.valueOf(lengthStr));
						return myFileWithDuration;
					}
				})
				.flatMap(new Func1<MyFileListWithDuration, Observable<ResponseBody>>() {
					@Override
					public Observable<ResponseBody> call(MyFileListWithDuration myFileListWithDuration) {

						File file = new File(filePath);
//						MediaDecoder mediaDecoder = new MediaDecoder(filePath);
//						String duration = mediaDecoder.getVedioFileLength();

						MediaType textType = MediaType.parse("text/plain");
						HttpRequestHead httphead = new HttpRequestHead();
						String json = JSON.toJSONString(httphead);
						String md5 = null;
						try {
							md5 = Md5Utils.fileMD5(file.getAbsolutePath());
						} catch (IOException e) {
							e.printStackTrace();
						}

						MultipartBody.Builder builder = new MultipartBody.Builder()
								.setType(MultipartBody.FORM)
								.addFormDataPart("head", MyFileSender.Base64Utils.getBase64(json))
								.addFormDataPart("duration", String.valueOf(myFileListWithDuration.getDuration()))
								.addFormDataPart("name", String.valueOf(filePath))
								.addFormDataPart("video_create_time", String.valueOf(file.lastModified()))
								.addFormDataPart("video_md5", String.valueOf(file.lastModified()));
						if(myFileListWithDuration!=null){
							for (int i = 0; i < myFileListWithDuration.getFile().size(); i++) {
								builder.addFormDataPart("preview_img" + i, myFileListWithDuration.getFile().get(i).getName(), RequestBody.create(MediaType.parse("image/jpeg"), myFileListWithDuration.getFile().get(i)));
							}
						}
						MultipartBody  body = builder.build();
						return MyRetrofitFactory.getSendAPISingleton().uploadVideoImgs(body);
					}
				}).subscribe(new Subscriber<ResponseBody>() {
					@Override
					public void onCompleted() {
						AXLog.e("wzytest", "on fileUtil onCompleted");
						//删除压缩文件
//						for (File f:myFileWithDuration) {
//							if(f.exists()&&f.isFile()){
//								f.delete();
//							}
//						}
					}

					@Override
					public void onNext(ResponseBody o) {
						try {
							AXLog.e("wzytest", "onNext :" + o.string());
						} catch (IOException e) {
							e.printStackTrace();
						}
					}

					@Override
					public void onError(Throwable e) {
						AXLog.e("wzytest", "onError :" + e.getCause() + " :" + e.getMessage());
						e.printStackTrace();
					}

					@Override
					public void onStart() {
						super.onStart();
						//AXLog.e("wzytest", "onStart");
					}
				});


	}

	public static void fileUploadByPath(final String filePath) throws IOException {
		Subscription subscribe = Observable.just(filePath)
				.subscribeOn(Schedulers.io())
				.map(new Func1<String, File>() {
					@Override
					public File call(String s) {
						//图片压缩后的文件
						Bitmap bitmap = BitmapFactory.decodeFile(s);
						File thumbFile = null;
						try {
							File file = new File(s);

							thumbFile = new File(file.getAbsolutePath().replace(file.getName(), "_thumb" + file.getName()));
							FileOutputStream thumbOutStream = new FileOutputStream(thumbFile);
							bitmap.compress(Bitmap.CompressFormat.JPEG, 20, thumbOutStream);

						} catch (Exception e) {
							e.printStackTrace();
						}
						return thumbFile;
					}
				})
				.flatMap(new Func1<File, Observable<ResponseBody>>() {
					@Override
					public Observable<ResponseBody> call(File file) {
						AXLog.e("wzytest", "on call:" + file.getAbsolutePath());
//                        MediaType textType = MediaType.parse("text/plain");
						HttpRequestHead httphead = new HttpRequestHead();
						String json = JSON.toJSONString(httphead);
//                        RequestBody head = RequestBody.create(textType, MyFileSender.Base64Utils.getBase64(json));
//                        RequestBody time = RequestBody.create(textType, String.valueOf(file.lastModified()));
//                        RequestBody fileMd5 = null;
//                        try {
//                            fileMd5 = RequestBody.create(textType, Md5Utils.fileMD5(file.getAbsolutePath()));
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
//                        RequestBody path = RequestBody.create(textType, file.getAbsoluteFile());
//
						RequestBody body = RequestBody.create(MediaType.parse(MULTIPART_FORM_DATA), file);
//
						MultipartBody.Part filePart = MultipartBody.Part.createFormData("photo", file.getAbsolutePath(),body);
						MultipartBody.Part head = MultipartBody.Part.createFormData("head",MyFileSender.Base64Utils.getBase64(json) );
						MultipartBody.Part time = MultipartBody.Part.createFormData("file_last_modify_time",  String.valueOf(file.lastModified()) );
						MultipartBody.Part fileMd5 = null;
						try {
							fileMd5 = MultipartBody.Part.createFormData("file_md5", Md5Utils.fileMD5(file.getAbsolutePath()));
						} catch (IOException e) {
							e.printStackTrace();
						}
						MultipartBody.Part path = MultipartBody.Part.createFormData("file_path", file.getAbsolutePath());

						MultipartBody multipartBody = new MultipartBody.Builder().addPart(filePart)
								.addPart(head)
								.addPart(time)
								.addPart(fileMd5)
								.addPart(path).build();

						return MyRetrofitFactory.getSendAPISingleton().uploadImgs(multipartBody);
//                        return MyRetrofitFactory.getSendAPISingleton().uploadImgByParts(head, time, filePart, fileMd5, path);
					}
				})
				.subscribe(new Subscriber<ResponseBody>() {
					@Override
					public void onCompleted() {
						AXLog.e("wzytest", "onCompleted");
						//删除压缩文件
					}

					@Override
					public void onNext(ResponseBody o) {
						try {
							AXLog.e("wzytest", "onNext :" + o.string());
						} catch (IOException e) {
							e.printStackTrace();
						}
					}

					@Override
					public void onError(Throwable e) {
						AXLog.e("wzytest", "onError :" + e.getCause() + " :" + e.getMessage());
						e.printStackTrace();
					}

					@Override
					public void onStart() {
						super.onStart();
						AXLog.e("wzytest", "onStart");
					}


				});
	}


	private static class MyFileListWithDuration {
		List<File> file;

		public List<File> getFile() {
			return file;
		}

		public void setFile(List<File> file) {
			this.file = file;
		}

		public  long duration ;

		public long getDuration() {
			return duration;
		}

		public  void setDuration(long duration) {
			duration = duration;
		}

		public MyFileListWithDuration(List<File> frameFile) {
			this.file = frameFile;
		}

		public MyFileListWithDuration() {

		}
	}
}
